:-include('chessRules').

weight(queen,980).
weight(rook,520).
weight(bishop,330).
weight(knight,330).
weight(pawn,100).
weight(king,0).
weight(threat,0.40).
weight(force,0.60).                                        
                                        


%evaluateForceCell(piece(Piece,Player),Player,Value):-weight(Piece,Value).
%evaluateForceCell(piece(Piece,Player),Turn,Value):-adversary(Player,Turn),weight(Piece,Val1),Value is Val1 * -1.
%evaluateForceCell(empty,_,0).
evaluateForceCell(empty,0).
evaluateForceCell(piece(Piece,white),Value):-weight(Piece,Value),!.
evaluateForceCell(piece(Piece,black),Value):-weight(Piece,Val1), Value is Val1 * -1.

%evaluateForceRow([H|T],Player,Value):-evaluateForceCell(H,Player,Val1),evaluateForceRow(T,Player,Val2),Value is Val1 + Val2.
evaluateForceRow([],0).
evaluateForceRow([H|T],Value):-evaluateForceCell(H,Val1),evaluateForceRow(T,Val2),Value is Val1 + Val2.

%evaluateForceBoard([],_,0).
%evaluateForceBoard([R|T],Player,Value):-evaluateForceRow(R,Player,Val1),evaluateForceBoard(T,Player,Val2), Value is Val1 + Val2.
evaluateForceBoard([],0).
evaluateForceBoard([R|T],Value):-evaluateForceRow(R,Val1),evaluateForceBoard(T,Val2), Value is Val1 + Val2.

%evaluateThreatBoard(Board,SS,Player,Value):-aggregate_all(sum(Value2),evaluateThreatBoard1(Board,SS,Player,Value2),Value).
%evaluateThreatBoard1(Board,SS,Player,Value):-ch_range(X),ch_range(Y),evaluateThreatCell(Board,SS,X,Y,Player,Value).
evaluateThreatBoard(Board,SS,Value):-aggregate_all(sum(Value2),evaluateThreatBoard1(Board,SS,Value2),Value).
evaluateThreatBoard1(Board,SS,Value):-ch_range(X),ch_range(Y),evaluateThreatCell(Board,SS,X,Y,Value).

%evaluateThreatCell(Board,SS,SX,SY,Player,Value):-aggregate_all(count, threat(Board,SS,SX,SY,TX,TY,Player), Count1),
%                                        adversary(Player,Player2),aggregate_all(count, threat(Board,SS,SX,SY,TX,TY,Player2), Count2),
%                                        bigger(Count1,Count2,Value).
%Probables Moves... fixit
%evaluateThreatCell(Board,SS,SX,SY,Value):-										aggregate_all(count, threat(BoardW,SS,SX,SY,TX,TY,white), Count1),
%                                        aggregate_all(count, threat(BoardB,SS,SX,SY,TX,TY,black), Count2),
%                                        bigger(Count1,Count2,Value).
evaluateThreatCell(Board,SS,SX,SY,Value):-rpMxT(Board,SX,SY,piece(pawn,black),BoardW),
										rpMxT(Board,SX,SY,piece(pawn,white),BoardB),
										aggregate_all(count, threat(BoardW,SS,SX,SY,TX,TY,white), Count1),
                                        aggregate_all(count, threat(BoardB,SS,SX,SY,TX,TY,black), Count2),
                                        bigger(Count1,Count2,Value2),Value is Value2 * 10.
                                        
evaluateBoard(Board,SS,-10000):-checkMate(Board,SS,white).
evaluateBoard(Board,SS,10000):-checkMate(Board,SS,black).
evaluateBoard(Board,SS,Value):-evaluateForceBoard(Board,Value1),evaluateThreatBoard(Board,SS,Value2),
                               weight(threat,W1),weight(force,W2),Value is Value1 * W1 + Value2 * W2.
                              % write(Board),write(Value).
%evaluateBoard(Board,_,Value):-evaluateForceBoard(Board,Value).
										
bigger(A,B,Res):-A > B,Res is 1,!.
bigger(A,B,Res):-A < B, Res is -1,!.
bigger(A,B,Res):-A = B, Res is 0.										
max(A,B,Res):-A >= B,Res = A.
max(A,B,Res):-A < B, Res = B.

max_to_move(white).
min_to_move(black).

%% The alpha-beta algorithm

alphaB( Player,Board,SS, GSX,GSY,GTX,GTY, Val,D)  :-
alphabeta( Player, Board,SS, -2000,2000, _,GSX,GSY,GTX,GTY, Val,D).

alphabeta(_Player, Board,SS, _Alpha, _Beta, _GoodPos,_GSX,_GSY,_GTX,_GTY, Val,0)  :-
%evaluateForceBoard(Board,Val),!.                             % Static value of Pos 
evaluateBoard(Board,SS,Val),!, %pb(Board,PB),
  writeln(Val).
                             % Static value of Pos 

alphabeta( Player, Board,SS, Alpha, Beta, GoodPos,GSX,GSY,GTX,GTY, Val,Deep)  :-
%    Deep > 1
  findall((SX,SY,TX,TY,TB,TS),getMove(Board,SS,SX,SY,TB,TS,TX,TY,Player),Moves),!,
  adversary(Player,OtherPlayer),
  D is Deep - 1,
%  moves( Pos, PosList), !,
  boundedbest( OtherPlayer,Moves, Alpha, Beta, GoodPos,GSX,GSY,GTX,GTY, Val,D);
%  writeln([GSX,GSY,GTX,GTY,Alpha,Beta]);
 evaluateBoard(Board,SS,Val).                             % Static value of Pos 
 
level(Deep,W):- S is 3 - Deep, S3 is S * 3, addW(' ',S3,W).
addW(O,0,O).
addW(O,D,U):- D1 is D -1, addW(O,D1,U2), concat(' ',U2,U).

boundedbest( Player,[(SX,SY,TX,TY,TB,TS) | Moves], Alpha, Beta, GoodPos,GSX,GSY,GTX,GTY, GoodVal,Deep)  :-
%  adversary(Player,OtherPlayer),
%  level(Deep,W),
%  write([W,evaluando_hijos_de,SX,SY,TX,TY]),
  alphabeta(Player, TB,TS, Alpha, Beta, _GoodPos,_GSX,_GSY,_GTX,_GTY, Val,Deep),
  goodenough( Player,Moves, Alpha, Beta, TB, SX,SY,TX,TY,Val, GoodPos,GSX,GSY,GTX,GTY, GoodVal,Deep).

goodenough( _Player,[], _, _, Pos,SX,SY,TX,TY, Val, Pos,SX,SY,TX,TY, Val,_Deep)  :-  !.    % No other candidate

goodenough( Player,_, Alpha, Beta, Pos,SX,SY,TX,TY, Val, Pos,SX,SY,TX,TY, Val,_Deep)  :-
  min_to_move( Player), Val > Beta, !                   % Maximizer attained upper bound
  ;
  max_to_move( Player), Val < Alpha, !.                 % Minimizer attained lower bound

goodenough( Player,PosList, Alpha, Beta, Pos,SX,SY,TX,TY, Val, GoodPos,GSX,GSY,GTX,GTY, GoodVal,Deep)  :-
  newbounds( Player,Alpha, Beta, Val, NewAlpha, NewBeta),    % Refine bounds  
  boundedbest( Player,PosList, NewAlpha, NewBeta, Pos1, SX1,SY1,TX1,TY1,Val1,Deep),
  betterof( Player,Pos,SX,SY,TX,TY, Val, Pos1,SX1,SY1,TX1,TY1, Val1, GoodPos,GSX,GSY,GTX,GTY, GoodVal).

newbounds( Player, Alpha, Beta, Val, Val, Beta)  :-
  min_to_move( Player), Val > Alpha, !.                 % Maximizer increased lower bound 

newbounds( Player, Alpha, Beta, Val, Alpha, Val)  :-
   max_to_move( Player), Val < Beta, !.                 % Minimizer decreased upper bound 

newbounds( _, Alpha, Beta, _, Alpha, Beta).          % Otherwise bounds unchanged 

betterof( Player,Pos,SX,SY,TX,TY, Val, _Pos1,_SX,_SY,_TX,_TY, Val1, Pos,SX,SY,TX,TY, Val)  :-        % Pos better than Pos1 
  min_to_move( Player), Val > Val1, !
  ;
  max_to_move( Player), Val < Val1, !.

betterof( _Player,_Pos,_SX,_SY,_TX,_TY, _Val, Pos1,SX1,SY1,TX1,TY1, Val1, Pos1,SX1,SY1,TX1,TY1, Val1).             % Otherwise Pos1 better


test:-initialBoard(Board,SS),findall((SX,SY,TX,TY,TB,TS),getMove(Board,SS,SX,SY,TB,TS,TX,TY,Player),Moves).
test2:-initialBoard(Board,SS),evaluateBoard(Board,SS,Val).